package com.hncboy.chatgpt.front.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import com.google.common.collect.Lists;
import com.hncboy.chatgpt.base.annotation.FrontPreAuth;
import com.hncboy.chatgpt.base.domain.entity.ChatCustomerDO;
import com.hncboy.chatgpt.front.service.CustomerService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static java.lang.Thread.sleep;

@FrontPreAuth
@AllArgsConstructor
@Tag(name = "chat相关工具接口")
@RestController
@RequestMapping
public class UtilsController {
    private static String uri = "https://southeastasia.api.speech.microsoft.com/accfreetrial/texttospeech/acc/v3.0-beta1/vcg/speak";
    @Resource
    private CustomerService customerServiceImpl;

    private static void extracted(String str, String name, String style, String role, String rate, String pitch, HttpServletResponse textToSpeechResponse) throws IOException {
        HashMap<String, String> headers = new HashMap<>();
        headers.put("authority", "southeastasia.api.speech.microsoft.com");
        headers.put("accept", "*/*");
        headers.put("accept-language", "zh-CN,zh;q=0.9");
        headers.put("customvoiceconnectionid", "d8a3a480-dd87-11ed-8758-97b5a7fbfaf6");
        headers.put("origin", "https://speech.microsoft.com");
        headers.put("sec-ch-ua", "\"Google Chrome\";v=\"111\", \"Not(A:Brand\";v=\"8\", \"Chromium\";v=\"111\"");
        headers.put("sec-ch-mobile", "?0");
        headers.put("sec-ch-platform", "\"Windows\"");
        headers.put("sec-fetch-dest", "empty");
        headers.put("sec-fetch-mode", "cors");
        headers.put("sec-fetch-site", "same-site");
        headers.put("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36");
        headers.put("content-type", "application/json");
        headers.put("response-type", "arraybuffer");
        String ssml = """
                 <speak xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="http://www.w3.org/2001/mstts" 
                        xmlns:emo="http://www.w3.org/2009/10/emotionml" version="1.0" xml:lang="en-US">
                        <voice name="${Name}">
                            <mstts:express-as style="${Style}">
                                <prosody rate="${Rate}" pitch="${Pitch}">
                                ${Text}
                                </prosody>
                            </mstts:express-as>
                        </voice>
                    </speak>
                """;
        String replace = ssml.replace("${Text}", str).replace("${Name}", name).replace("${Style}", style).replace("${Rate}", rate).replace("${Pitch}", pitch);

        HashMap<String, Object> body = new HashMap<>();
        body.put("ssml", replace);
        body.put("ttsAudioFormat", "audio-24khz-160kbitrate-mono-mp3");
        body.put("offsetInPlainText", 0);
        body.put("properties", Map.of("SpeakTriggerSource", "AccTuningPagePlayButton"));

        HttpResponse execute = HttpRequest.post(uri).addHeaders(headers).body(JSONUtil.toJsonStr(body)).execute();

        // 以流的形式返回
        InputStream inputStream = execute.bodyStream();

        OutputStream outputStream = new BufferedOutputStream(textToSpeechResponse.getOutputStream());
        //创建存放文件内容的数组
        byte[] buff = new byte[1024];
        //所读取的内容使用n来接收
        int n;
        //当没有读取完时,继续读取,循环
        while ((n = inputStream.read(buff)) != -1) {
            //将字节数组的数据全部写入到输出流中
            outputStream.write(buff, 0, n);
        }
        //强制将缓存区的数据进行输出
        outputStream.flush();
        //关流
        outputStream.close();
        inputStream.close();
    }

    @RequestMapping("/getFile")
    public void getFile(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType("audio/mp3"); // 设置返回的文件类型
        //读取路径下面的文件
        File picFile = new File("D:\\music\\test.mp3");
        //读取指定路径下面的文件
        InputStream in = new FileInputStream(picFile);
        OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
        //创建存放文件内容的数组
        byte[] buff = new byte[1024];
        //所读取的内容使用n来接收
        int n;
        //当没有读取完时,继续读取,循环
        while ((n = in.read(buff)) != -1) {
            //将字节数组的数据全部写入到输出流中
            outputStream.write(buff, 0, n);
        }
        //强制将缓存区的数据进行输出
        outputStream.flush();
        //关流
        outputStream.close();
        in.close();
    }


    @PostMapping("/toStream")
    public void returnStream(HttpServletResponse response) throws IOException {
        String message = "我是一段等待已流形式返回的文字";
//        File file = new File("C:\\Users\\limi\\Pictures\\DSC_0757.jpg");
        File file = new File("D:\\music\\test.mp3");

        // 以流的形式返回
        ServletOutputStream out = null;
        ByteArrayOutputStream baos = null;

        try {
            InputStream inStream = new FileInputStream(file);
            byte[] buffer = new byte[1024];
            int len;
            baos = new ByteArrayOutputStream();
            while ((len = inStream.read(buffer)) != -1) {
                baos.write(buffer, 0, len);
            }
            out = response.getOutputStream();
            out.write(baos.toByteArray());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            Objects.requireNonNull(baos).flush();
            baos.close();
            Objects.requireNonNull(out).flush();
            out.close();
        }

    }

    @Operation(summary = "文本转语音")
    @PostMapping("/txtToVoice")
    public void txtToVoice(@RequestBody Map<String, Object> paramMap, HttpServletResponse textToSpeechResponse) throws Exception {
        //获取翻译文本，计算长度，以500字做切割，每次切割时在500字前找最后一个中文句号，每隔3次睡眠1下
        String str = paramMap.get("ssml").toString();

        Long customerId = Long.valueOf(paramMap.get("customerId").toString());
        ChatCustomerDO customer = customerServiceImpl.getCustomer(customerId);
        if (BeanUtil.isEmpty(customer)) {
            throw new Exception("用户信息有误！！");
        }
        Integer isVip = customer.getIsVip();
        if (isVip != 1) {
            Integer limits = customer.getLimits();
            if (limits > 0) {
                limits -= 1;
                customer.setLimits(limits);
                customerServiceImpl.saveOrUpdate(customer);
            } else {
                throw new Exception("已达最大免费使用限制！");
            }
        }

        //控制语音属性
        String name = paramMap.get("name").toString();
        String style = paramMap.get("style").toString();
        String role = paramMap.get("role").toString();
        String rate = paramMap.get("rate").toString();
        String pitch = paramMap.get("pitch").toString();

        //循环切割，记录字符串，3次之后休眠
        List<String> textList = Lists.newArrayList();
        //text1用来获取500字，text2用来判断剩下字数
        String text;
        if (str.length() > 500) {
            do {
                text = str.substring(0, 500);
                //获取剩下内容
                str = str.substring(text.lastIndexOf("。"));
                //获取段落，
                text = text.substring(0, text.lastIndexOf("。"));
                textList.add(text);
            } while (str.length() > 500);
        } else {
            textList.add(str);
        }


        //循环转语音
        for (int i = 0; i < textList.size(); i++) {
            extracted(textList.get(i), name, style, role, rate, pitch, textToSpeechResponse);
            if ((i + 1) % 3 == 0) {
                sleep(1000);
            }
        }
    }

}
